package com.interview.rpc.proxy;

import com.interview.rpc.protocol.Request;
import com.interview.rpc.protocol.Response;
import com.interview.rpc.serialize.JsonSerializer;
import com.interview.rpc.serialize.Serializer;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * RPC代理类
 */
public class RpcProxy {
    
    private static final ConcurrentHashMap<String, RpcContext> pendingRequests = new ConcurrentHashMap<>();
    
    public static <T> T createProxy(Class<T> interfaceClass, String host, int port) {
        return (T) Proxy.newProxyInstance(
                interfaceClass.getClassLoader(),
                new Class[]{interfaceClass},
                new RpcInvocationHandler(host, port)
        );
    }
    
    private static class RpcInvocationHandler implements InvocationHandler {
        private String host;
        private int port;
        
        public RpcInvocationHandler(String host, int port) {
            this.host = host;
            this.port = port;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 构造请求
            Request request = new Request();
            request.setRequestId(UUID.randomUUID().toString());
            request.setClassName(method.getDeclaringClass().getName());
            request.setMethodName(method.getName());
            request.setParameterTypes(method.getParameterTypes());
            request.setParameters(args);
            
            // 创建上下文并放入等待集合
            RpcContext context = new RpcContext();
            pendingRequests.put(request.getRequestId(), context);
            
            try {
                // 发送请求（简化处理，实际应该通过网络发送）
                // 这里模拟发送和接收过程
                sendRequest(request, host, port);
                
                // 等待响应
                if (!context.latch.await(5, TimeUnit.SECONDS)) {
                    throw new RuntimeException("RPC调用超时");
                }
                
                Response response = context.response;
                if (response.getCode() != 200) {
                    throw new RuntimeException("RPC调用失败: " + response.getMessage());
                }
                
                return response.getData();
            } finally {
                pendingRequests.remove(request.getRequestId());
            }
        }
        
        private void sendRequest(Request request, String host, int port) {
            // 简化处理，实际应通过Netty发送请求
            // 这里仅用于演示，模拟直接调用处理方法
            new Thread(() -> {
                try {
                    // 模拟网络延迟
                    Thread.sleep(100);
                    
                    // 模拟服务端处理
                    Response response = handleRequest(request);
                    
                    // 获取上下文并设置响应
                    RpcContext context = pendingRequests.get(request.getRequestId());
                    if (context != null) {
                        context.response = response;
                        context.latch.countDown();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
        
        // 模拟服务端处理请求
        private Response handleRequest(Request request) {
            Response response = new Response();
            response.setRequestId(request.getRequestId());
            
            try {
                // 简化处理，实际应该根据接口和方法名找到对应的实现类并调用方法
                Class<?> clazz = Class.forName(request.getClassName());
                Object serviceBean = getServiceBean(clazz);
                
                Method method = clazz.getMethod(request.getMethodName(), request.getParameterTypes());
                Object result = method.invoke(serviceBean, request.getParameters());
                
                response.setCode(200);
                response.setMessage("success");
                response.setData(result);
            } catch (Exception e) {
                response.setCode(500);
                response.setMessage("服务器内部错误: " + e.getMessage());
                response.setData(null);
            }
            
            return response;
        }
        
        // 模拟获取服务实例
        private Object getServiceBean(Class<?> clazz) throws Exception {
            // 简化处理，实际应该从服务注册中心获取实例
            // 这里假设接口名以Service结尾，实现类以ServiceImpl结尾
            String implClassName = clazz.getName().replace("Service", "ServiceImpl");
            Class<?> implClass = Class.forName(implClassName);
            return implClass.newInstance();
        }
    }
    
    // RPC上下文，用于存储请求和响应的关联关系
    private static class RpcContext {
        private Response response;
        private CountDownLatch latch = new CountDownLatch(1);
    }
    
    // 用于服务端处理完请求后设置响应
    public static void setResponse(Response response) {
        RpcContext context = pendingRequests.get(response.getRequestId());
        if (context != null) {
            context.response = response;
            context.latch.countDown();
        }
    }
}